package util;

import java.io.FileInputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.encoders.Hex;

public class IntegrityTool {

	private static final String ALGORITHM = "HmacSHA256";
	
	private String pathToKey;
	private Key secretKey;
	
	public IntegrityTool(Config config) throws IOException {
		pathToKey = config.getString("hmac.key");
		
		//Read the shared secret Key
		byte[] keyBytes = new byte[1024];
		FileInputStream fis = new FileInputStream(pathToKey);
		fis.read(keyBytes);
		fis.close();
		
		byte[] input = Hex.decode(keyBytes);
		secretKey = new SecretKeySpec(input,ALGORITHM);
	}
	
	/**
	 * Creates a Base64 encoded HMAC from the given message
	 * 
	 * @param message The message to generate the hmac from
	 * @return the generated HMAC encoded in Base64
	 * @throws NoSuchAlgorithmException
	 * @throws InvalidKeyException
	 */
	public String createMac(String message) throws InvalidKeyException {
		
		Mac hMac = null;
		try {
			hMac = Mac.getInstance(ALGORITHM);
		} catch (NoSuchAlgorithmException e) {
			// Very unlikely to happen because algorithm is a final string
			e.printStackTrace();
		} 
		hMac.init(secretKey);
		hMac.update(message.getBytes());
		
		byte[] computedHash = hMac.doFinal();
		
		return new String(Base64.encode(computedHash));
	}
	
	/**
	 * Creates a HMAC from the given message and compares it to the receivedHash
	 * 
	 * @param message The plaintext message
	 * @param b64ReceivedHash The HMAC that was sent by the communication partner
	 * @return
	 * @throws InvalidKeyException
	 * @throws NoSuchAlgorithmException
	 */
	public boolean verifyMac(String message, String receivedHash) throws InvalidKeyException {
		
		byte[] computedHash = createMac(message).getBytes();

		return MessageDigest.isEqual(computedHash,receivedHash.getBytes());
	}
}